#nullable enable
using Godot;
using System.Collections.Generic;
using System.Linq;

namespace AndroidUnevenRoadGame.Game
{
    public static class EnemyDatabase
    {
        private static readonly Dictionary<string, EnemyDefinition> _enemies = new();
        private static readonly Dictionary<string, List<string>> _encounters = new();
        private static bool _isLoaded;

        public static void LoadFromJson(string resourcePath)
        {
            if (_isLoaded)
            {
                return;
            }

            var file = FileAccess.Open(resourcePath, FileAccess.ModeFlags.Read);
            if (file == null)
            {
                GD.PushWarning($"无法打开敌人配置：{resourcePath}");
                return;
            }

            var jsonText = file.GetAsText();
            file.Dispose();

            var result = Json.ParseString(jsonText);
            if (result.VariantType != Variant.Type.Dictionary)
            {
                GD.PushWarning("敌人配置格式错误：根节点需要为对象");
                return;
            }

            var rootDict = result.AsGodotDictionary();

            if (rootDict.TryGetValue("enemies", out var enemiesVar) &&
                enemiesVar.VariantType == Variant.Type.Array)
            {
                foreach (Variant entryVar in enemiesVar.AsGodotArray())
                {
                    if (entryVar.VariantType != Variant.Type.Dictionary)
                    {
                        continue;
                    }

                    var dict = entryVar.AsGodotDictionary();
                    var id = dict.TryGetValue("id", out var idVar) && idVar.VariantType == Variant.Type.String ? idVar.AsString() : "enemy";

                    var category = ParseCategory(dict.TryGetValue("category", out var categoryVar) && categoryVar.VariantType == Variant.Type.String
                        ? categoryVar.AsString()
                        : "normal");

                    var name = dict.TryGetValue("name", out var nameVar) && nameVar.VariantType == Variant.Type.String ? nameVar.AsString() : id;
                    var portrait = ResolvePortraitPath(dict, id);
                    var baseHp = ReadInt(dict, "max_hp", GetDefaultBaseHp(category));
                    var baseMinDamage = ReadInt(dict, "min_damage", GetDefaultMinDamage(category));
                    var baseMaxDamage = ReadInt(dict, "max_damage", GetDefaultMaxDamage(category));
                    var goldReward = ReadInt(dict, "gold_reward", GetDefaultGold(category));
                    var hpGrowth = ReadFloat(dict, "hp_growth", GetDefaultHpGrowth(category));
                    var damageGrowth = ReadFloat(dict, "damage_growth", GetDefaultDamageGrowth(category));

                    _enemies[id] = new EnemyDefinition(
                        id,
                        name,
                        category,
                        baseHp,
                        baseMinDamage,
                        baseMaxDamage,
                        goldReward,
                        hpGrowth,
                        damageGrowth,
                        portrait
                    );
                }
            }

            if (rootDict.TryGetValue("encounters", out var encountersVar) &&
                encountersVar.VariantType == Variant.Type.Dictionary)
            {
                var encountersDict = encountersVar.AsGodotDictionary();
                foreach (Variant encounterKey in encountersDict.Keys)
                {
                    var idsVar = encountersDict[encounterKey];
                    if (idsVar.VariantType == Variant.Type.Array)
                    {
                        var encounterId = encounterKey.AsString();
                        var ids = new List<string>();
                        foreach (Variant idEntry in idsVar.AsGodotArray())
                        {
                            if (idEntry.VariantType == Variant.Type.String)
                            {
                                ids.Add(idEntry.AsString());
                            }
                        }

                        _encounters[encounterId] = ids;
                    }
                }
            }

            _isLoaded = true;
        }

        public static EnemyDefinition Get(string id)
        {
            if (_enemies.TryGetValue(id, out var definition))
            {
                return definition;
            }

            GD.PushWarning($"未找到敌人：{id}");
            return new EnemyDefinition(
                id,
                id,
                EnemyCategory.Normal,
                GetDefaultBaseHp(EnemyCategory.Normal),
                GetDefaultMinDamage(EnemyCategory.Normal),
                GetDefaultMaxDamage(EnemyCategory.Normal),
                GetDefaultGold(EnemyCategory.Normal),
                GetDefaultHpGrowth(EnemyCategory.Normal),
                GetDefaultDamageGrowth(EnemyCategory.Normal),
                $"res://Assets/Textures/Enemies/{id}.jpg");
        }

        public static List<EnemyDefinition> GetEncounter(string encounterId)
        {
            var result = new List<EnemyDefinition>();
            if (_encounters.TryGetValue(encounterId, out var ids))
            {
                foreach (var id in ids)
                {
                    result.Add(Get(id));
                }
            }
            else
            {
                GD.PushWarning($"未找到遭遇战：{encounterId}");
            }
            return result;
        }

        public static string? GetRandomEncounterId(string prefix, RandomNumberGenerator rng)
        {
            var matches = _encounters.Keys.Where(key => key.StartsWith(prefix)).ToList();
            if (matches.Count == 0)
            {
                return null;
            }

            var index = rng.RandiRange(0, matches.Count - 1);
            return matches[index];
        }

        private static string ResolvePortraitPath(Godot.Collections.Dictionary dict, string id)
        {
            if (dict.TryGetValue("portrait_path", out var portraitPathVar) && portraitPathVar.VariantType == Variant.Type.String)
            {
                return portraitPathVar.AsString();
            }

            if (dict.TryGetValue("portrait", out var portraitVar) && portraitVar.VariantType == Variant.Type.String)
            {
                return portraitVar.AsString();
            }

            return $"res://Assets/Textures/Enemies/{id}.jpg";
        }

        private static EnemyCategory ParseCategory(string raw)
        {
            return raw.ToLowerInvariant() switch
            {
                "elite" => EnemyCategory.Elite,
                "boss" => EnemyCategory.Boss,
                _ => EnemyCategory.Normal
            };
        }

        private static int ReadInt(Godot.Collections.Dictionary dict, string key, int fallback)
        {
            if (!dict.TryGetValue(key, out var value))
            {
                return fallback;
            }

            return value.VariantType switch
            {
                Variant.Type.Int => value.AsInt32(),
                Variant.Type.Float => Mathf.RoundToInt((float)value.AsDouble()),
                _ => fallback
            };
        }

        private static float ReadFloat(Godot.Collections.Dictionary dict, string key, float fallback)
        {
            if (!dict.TryGetValue(key, out var value))
            {
                return fallback;
            }

            return value.VariantType switch
            {
                Variant.Type.Float => (float)value.AsDouble(),
                Variant.Type.Int => value.AsInt32(),
                _ => fallback
            };
        }

        private static int GetDefaultBaseHp(EnemyCategory category) => category switch
        {
            EnemyCategory.Elite => 48,
            EnemyCategory.Boss => 85,
            _ => 24
        };

        private static int GetDefaultMinDamage(EnemyCategory category) => category switch
        {
            EnemyCategory.Elite => 5,
            EnemyCategory.Boss => 8,
            _ => 2
        };

        private static int GetDefaultMaxDamage(EnemyCategory category) => category switch
        {
            EnemyCategory.Elite => 8,
            EnemyCategory.Boss => 12,
            _ => 5
        };

        private static int GetDefaultGold(EnemyCategory category) => category switch
        {
            EnemyCategory.Elite => 55,
            EnemyCategory.Boss => 140,
            _ => 20
        };

        private static float GetDefaultHpGrowth(EnemyCategory category) => category switch
        {
            EnemyCategory.Elite => 0.06f,
            EnemyCategory.Boss => 0.08f,
            _ => 0.04f
        };

        private static float GetDefaultDamageGrowth(EnemyCategory category) => category switch
        {
            EnemyCategory.Elite => 0.05f,
            EnemyCategory.Boss => 0.07f,
            _ => 0.03f
        };
    }
}

